package com.example.demo.task;

import com.example.demo.dto.TaskInfoDTO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadLocalRandom;

@Service
public class TaskManagerService {

    @Autowired
    private ThreadPoolTaskScheduler scheduler;

    // Spring自动注入所有TaskExecutor实现类
    @Autowired
    private Map<String, TaskExecutor> taskExecutorMap;

    private Map<String, ScheduledFuture<?>> taskFutureMap = new ConcurrentHashMap<>();

    private Map<String, TaskInfo> taskInfoMap = new ConcurrentHashMap<>();

    /**
     * 添加定时任务
     * @param taskInfoDTO
     * @return 是否添加成功
     */
    public boolean addTask(TaskInfoDTO taskInfoDTO) {
        TaskInfo taskInfo = new TaskInfo();
        BeanUtils.copyProperties(taskInfoDTO, taskInfo);
        taskInfo.setId(generate().toString());
        // 校验参数
        if (taskFutureMap.containsKey(taskInfo.getId())) {
            throw new RuntimeException("任务ID已存在：" + taskInfo.getId());
        }
        if (!CronExpression.isValidExpression(taskInfo.getCronExpression())) {
            throw new RuntimeException("Cron表达式无效：" + taskInfo.getCronExpression());
        }
        if (!taskExecutorMap.containsKey(taskInfo.getTaskName())) {
            throw new RuntimeException("任务执行器不存在：" + taskInfo.getTaskName());
        }
        // 获取任务执行器
        TaskExecutor taskExecutor = taskExecutorMap.get(taskInfo.getTaskName());

        // 调度任务并存储Future对象
        ScheduledFuture<?> future = scheduler.schedule(
                () -> TaskRequestExecutor.exec(taskInfo, taskExecutor),
                new CronTrigger(taskInfo.getCronExpression())
        );
        // 存储任务信息
        taskInfo.setStatus(1);
        taskInfo.setNextExecutionTime(TaskRequestExecutor.calculateNextExecution(taskInfo.getCronExpression()));
        taskFutureMap.put(taskInfo.getId(), future);
        taskInfoMap.put(taskInfo.getId(), taskInfo);
        return true;
    }

    /**
     * 暂停定时任务
     * @param taskId 任务ID
     * @return 是否暂停成功
     */
    public boolean pauseTask(String taskId) {
        ScheduledFuture<?> future = taskFutureMap.get(taskId);
        if (future == null) {
            throw new RuntimeException("任务不存在：" + taskId);
        }
        if (future.isCancelled()) {
            throw new RuntimeException("任务已暂停：" + taskId);
        }
        // 取消任务（参数true表示如果任务正在执行则中断）
        boolean result = future.cancel(false);
        if (result) {
            TaskInfo taskInfo = taskInfoMap.get(taskId);
            taskInfo.setStatus(2);
            taskInfo.setNextExecutionTime(null);
        }
        return result;
    }

    /**
     * 恢复定时任务
     * @param taskId 任务ID
     * @return 是否恢复成功
     */
    public boolean resumeTask(String taskId) {
        TaskInfo taskInfo = taskInfoMap.get(taskId);
        if (taskInfo == null) {
            throw new RuntimeException("任务不存在：" + taskId);
        }
        if (Objects.nonNull(taskInfo.getStatus()) && taskInfo.getStatus().equals(1)) {
            throw new RuntimeException("任务已在运行：" + taskId);
        }
        // 重新调度任务
        TaskExecutor taskExecutor = taskExecutorMap.get(taskInfo.getTaskName());
        ScheduledFuture<?> future = scheduler.schedule(
                () -> TaskRequestExecutor.exec(taskInfo, taskExecutor),
                new CronTrigger(taskInfo.getCronExpression())
        );
        // 更新任务状态
        taskFutureMap.put(taskId, future);
        taskInfo.setStatus(1);
        taskInfo.setNextExecutionTime(TaskRequestExecutor.calculateNextExecution(taskInfo.getCronExpression()));
        return true;
    }

    /**
     * 删除定时任务
     * @param taskId 任务ID
     * @return 是否删除成功
     */
    public boolean deleteTask(String taskId) {
        ScheduledFuture<?> future = taskFutureMap.get(taskId);
        if (future != null) {
            future.cancel(true); // 强制取消任务
        }
        taskFutureMap.remove(taskId);
        taskInfoMap.remove(taskId);
        return true;
    }

    /**
     * 查询所有任务
     */
    public List<TaskInfo> getAllTasks() {
        return new ArrayList<>(taskInfoMap.values());
    }

    /**
     * 根据ID查询任务
     */
    public TaskInfo getTaskById(String taskId) {
        return taskInfoMap.get(taskId);
    }

    /**
     * 立即执行一次
     */
    public void runOnce(String id) {
        TaskInfo taskInfo = taskInfoMap.get(id);
        TaskExecutor taskExecutor = taskExecutorMap.get(id);
        if (taskInfo == null) throw new IllegalArgumentException("任务不存在");
        scheduler.submit(()->{
            taskExecutor.execute(taskInfo.getParams());
            taskInfo.setNextExecutionTime(TaskRequestExecutor.calculateNextExecution(taskInfo.getCronExpression()));
            taskInfo.setLastExecutionTime(LocalDateTime.now());
        });
    }

    // 上一次生成UUID的时间戳和序列号
    private static volatile long lastTimestamp = 0;
    private static volatile short sequence = 0;

    public static synchronized UUID generate() {
        long timestamp = Instant.now().toEpochMilli();
        // 如果是同一毫秒，增加序列号
        if (timestamp == lastTimestamp) {
            sequence++;
            if (sequence > 0xFFF) { // 12位序列号最大值
                // 等待下一毫秒
                while (timestamp <= lastTimestamp) {
                    timestamp = Instant.now().toEpochMilli();
                }
                sequence = 0;
            }
        } else {
            sequence = 0;
        }

        lastTimestamp = timestamp;

        // 48位时间戳（高16位和低32位）
        long timeHigh = (timestamp >>> 32) & 0xFFFFL;
        long timeLow = timestamp & 0xFFFFFFFFL;

        // 12位序列号
        int seq = sequence & 0xFFF;

        // 62位随机数
        long randB = ThreadLocalRandom.current().nextLong() & 0x3FFFFFFFFFFFFFFFL;

        // 组合各部分
        long mostSigBits = (timeLow << 32) | (timeHigh << 16) | (0x7L << 12) | seq;
        long leastSigBits = (0x2L << 62) | randB;

        return new UUID(mostSigBits, leastSigBits);
    }
}